/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.util;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import lombok.Getter;
import lombok.Setter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;

public class ControllerDependencyAnalyzer {

    // 用于存储每个文件的信息
    @Getter
    @Setter
    public static class FileStat {
        String className;
        String filePath;
        long sizeInBytes;
        long lines;

        public FileStat(String className, String filePath, long sizeInBytes, long lines) {
            this.className = className;
            this.filePath = filePath;
            this.sizeInBytes = sizeInBytes;
            this.lines = lines;
        }
    }

    // 用于存储 Controller 类的信息
    @Getter
    @Setter
    public static class ControllerInfo {
        @JsonProperty("controllerName")
        private String controllerName;

        @JsonProperty("dependentFiles")
        private List<FileStat> dependentFiles;

        @JsonProperty("totalLines")
        private long totalLines;

        @JsonProperty("totalSize")
        private long totalSize;

        // 无参构造函数
        public ControllerInfo() {
        }

        public ControllerInfo(String controllerName) {
            this.controllerName = controllerName;
            this.dependentFiles = new ArrayList<>();
            this.totalLines = 0;
            this.totalSize = 0;
        }
    }

    public static void main(String[] args) throws IOException {
        String modulesRootPath = "D:\\code2\\isfd-back\\comacins-common";
        File modulesRoot = new File(modulesRootPath);
        File[] moduleDirs = modulesRoot.listFiles(File::isDirectory);

        List<Map<String, Object>> moduleStats = new ArrayList<>();

        boolean hasValidSubModule = false;

        if (moduleDirs != null) {
            for (File moduleDir : moduleDirs) {
                File srcMainJava = new File(moduleDir, "src/main/java");
                if (srcMainJava.exists()) {
                    hasValidSubModule = true;
                    Map<String, Object> moduleResult = analyzeSingleModule(moduleDir.getName(), srcMainJava);
                    if (moduleResult != null) {
                        moduleStats.add(moduleResult);
                    }
                }
            }
        }

        // 如果没有有效子模块，认为根目录就是一个模块
        if (!hasValidSubModule) {
            File srcMainJava = new File(modulesRoot, "src/main/java");
            if (srcMainJava.exists()) {
                Map<String, Object> singleModuleResult = analyzeSingleModule(modulesRoot.getName(), srcMainJava);
                if (singleModuleResult != null) {
                    moduleStats.add(singleModuleResult);
                }
            }
        }

        // 输出结果
        Map<String, Object> finalResult = new LinkedHashMap<>();
        finalResult.put("moduleStats", moduleStats);

        ObjectMapper objectMapper = new ObjectMapper();
        try (FileWriter fileWriter = new FileWriter("controller_analysis_common.json")) {
            objectMapper.writerWithDefaultPrettyPrinter().writeValue(fileWriter, finalResult);
        }

        System.out.println("分析完成，结果写入 controller_analysis_admin.json");
    }



    private static Map<String, Object> analyzeSingleModule(String moduleName, File baseDir) {
        List<ControllerInfo> controllerInfos = new ArrayList<>();
        Map<String, File> classNameToFileMap = buildClassNameFileMap(baseDir);

        List<File> controllers = findAllControllers(baseDir);
        Set<String> globalVisitedClassNames = new HashSet<>();
        long globalTotalLines = 0;
        long globalTotalSize = 0;

        for (File controllerFile : controllers) {
            FileStat controllerFileStat = analyzeClassFile(controllerFile);
            ControllerInfo controllerInfo = new ControllerInfo(controllerFile.getName());

            if (controllerFileStat != null) {
                controllerInfo.dependentFiles.add(controllerFileStat);
                controllerInfo.totalLines += controllerFileStat.lines;
                controllerInfo.totalSize += controllerFileStat.sizeInBytes;

                if (globalVisitedClassNames.add(controllerFileStat.className)) {
                    globalTotalLines += controllerFileStat.lines;
                    globalTotalSize += controllerFileStat.sizeInBytes;
                }
            }

            List<FileStat> dependencies = analyzeClassDependencies(controllerFile, classNameToFileMap);
            for (FileStat dependency : dependencies) {
                controllerInfo.dependentFiles.add(dependency);
                controllerInfo.totalLines += dependency.lines;
                controllerInfo.totalSize += dependency.sizeInBytes;

                if (globalVisitedClassNames.add(dependency.className)) {
                    globalTotalLines += dependency.lines;
                    globalTotalSize += dependency.sizeInBytes;
                }
            }

            controllerInfos.add(controllerInfo);
        }

        if (controllers.isEmpty()) return null;

        Map<String, Object> moduleResult = new LinkedHashMap<>();
        moduleResult.put("moduleName", moduleName);
        moduleResult.put("controllerCount", controllers.size());
        moduleResult.put("totalLines", globalTotalLines);
        moduleResult.put("totalSize", globalTotalSize);
        moduleResult.put("controllers", controllerInfos);

        return moduleResult;
    }


    // 查找所有 Controller 类（带有 @RestController 或 @Controller 注解）
    private static List<File> findAllControllers(File directory) {
        List<File> controllers = new ArrayList<>();

        if (directory.isDirectory()) {
            for (File file : Objects.requireNonNull(directory.listFiles())) {
                if (file.isDirectory()) {
                    controllers.addAll(findAllControllers(file));
                } else if (file.getName().endsWith(".java")) {
                    // 检查该文件是否包含 @Controller 或 @RestController 注解
                    if (isController(file)) {
                        controllers.add(file);
                    }
                }
            }
        }
        return controllers;
    }

    // 判断类是否是 Controller（通过注解判断）
    private static boolean isController(File file) {
        try {
            String content = new String(Files.readAllBytes(file.toPath()));
            JavaParser javaParser = new JavaParser();
            CompilationUnit compilationUnit = javaParser.parse(content).getResult().orElseThrow(() -> new RuntimeException("Failed to parse Java content"));


            return compilationUnit.findAll(ClassOrInterfaceDeclaration.class).stream()
                .anyMatch(clazz -> clazz.getAnnotations().stream()
                    .anyMatch(annotation -> annotation.getNameAsString().equals("RestController") || annotation.getNameAsString().equals("Controller")));
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    // 分析单个类文件，获取文件的行数和大小
    private static FileStat analyzeClassFile(File file) {
        try {
            String className = file.getName().replace(".java", "");
            String filePath = file.getPath();
            long sizeInBytes = Files.size(file.toPath());
            long lines = Files.lines(file.toPath()).count();

            return new FileStat(className, filePath, sizeInBytes, lines);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static List<FileStat> analyzeClassDependencies(File classFile, Map<String, File> classNameToFileMap) {
        Set<String> visited = new HashSet<>();
        List<FileStat> allDependencies = new ArrayList<>();

        analyzeRecursively(classFile, classNameToFileMap, visited, allDependencies);
        return allDependencies;
    }

    private static void analyzeRecursively(File file,
                                           Map<String, File> classNameToFileMap,
                                           Set<String> visited,
                                           List<FileStat> collected) {
        try {
            String content = new String(Files.readAllBytes(file.toPath()));
            JavaParser javaParser = new JavaParser();
            CompilationUnit cu = javaParser.parse(content).getResult().orElseThrow(() -> new RuntimeException("Failed to parse Java content"));


            // 当前类名
            String currentClassName = file.getName().replace(".java", "");
            if (visited.contains(currentClassName)) return;
            visited.add(currentClassName);

            // 收集 import 语句中的依赖类
            for (var importDecl : cu.getImports()) {
                if (!importDecl.isAsterisk()) {
                    String fullClassName = importDecl.getNameAsString();
                    String simpleClassName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);

                    if (!visited.contains(simpleClassName) && classNameToFileMap.containsKey(simpleClassName)) {
                        File dependencyFile = classNameToFileMap.get(simpleClassName);
                        FileStat depStat = analyzeClassFile(dependencyFile);
                        if (depStat != null) {
                            collected.add(depStat);
                            // 递归处理依赖的依赖
                            analyzeRecursively(dependencyFile, classNameToFileMap, visited, collected);
                        }
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    // 在开始时构建类名到文件映射
    private static Map<String, File> buildClassNameFileMap(File baseDir) {
        Map<String, File> classFileMap = new HashMap<>();

        Queue<File> queue = new LinkedList<>();
        queue.add(baseDir);

        while (!queue.isEmpty()) {
            File current = queue.poll();
            if (current.isDirectory()) {
                File[] children = current.listFiles();
                if (children != null) Collections.addAll(queue, children);
            } else if (current.getName().endsWith(".java")) {
                try {
                    String content = new String(Files.readAllBytes(current.toPath()));
                    JavaParser javaParser = new JavaParser();
                    CompilationUnit cu = javaParser.parse(content).getResult().orElseThrow(() -> new RuntimeException("Failed to parse Java content"));

                    // 优先取首个顶层类型（class、interface、enum等）
                    cu.getTypes().stream().findFirst().ifPresent(type -> {
                        String className = type.getNameAsString();
                        classFileMap.put(className, current);
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return classFileMap;
    }


}
